package com.infore.remoteControl.service.impl;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Set;

import javax.persistence.EntityManager;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;

import com.infore.remoteControl.constant.Constants;
import com.infore.remoteControl.constant.InstructionConstants;
import com.infore.remoteControl.constant.ResultConstants;
import com.infore.remoteControl.dto.InstructionsDto;
import com.infore.remoteControl.entity.instructionsEntity.Instructions;
import com.infore.remoteControl.entity.instructionsEntity.InstructionsData;
import com.infore.remoteControl.entity.instructionsEntity.InstructionsType;
import com.infore.remoteControl.enums.InstructionsStateEnum;
import com.infore.remoteControl.enums.ResultStatus;
import com.infore.remoteControl.repository.IInstructionRepository;
import com.infore.remoteControl.repository.IInstructionTypeRepository;
import com.infore.remoteControl.select.QueryDispatcher;
import com.infore.remoteControl.select.dto.QueryParamDto;
import com.infore.remoteControl.select.util.QueryUtil;
import com.infore.remoteControl.service.InstructionsDataService;
import com.infore.remoteControl.service.InstructionsService;
import com.infore.remoteControl.util.MyBeanUtils;
import com.infore.remoteControl.util.PageUtil;
import com.infore.remoteControl.util.ResultEntity;

@Service
public class InstructionsServiceImpl implements InstructionsService {
	
	@Autowired
	IInstructionRepository iInstructionRepository;
	
	@Autowired
	IInstructionTypeRepository iInstructionTypeRepository;
	
	@Autowired
	EntityManager entityManager;
	
	@Autowired
	QueryDispatcher queryDispatcher;
	
	@Autowired
	InstructionsDataService instructionsDataService;
	
	@Override
	public ResultEntity query(QueryParamDto queryParamDto) {
		if (queryParamDto == null) { // 无查询条件
			return new ResultEntity(ResultStatus.SUCCESS, Constants.QUERY_SUCCESS)
					.setDataList(iInstructionRepository.findByOrderByNumbers());
		} else if (queryParamDto.getPageObject() != null && queryParamDto.getQueryCondition() == null
				&& queryParamDto.getAssembleCondition() == null && queryParamDto.getAssembleSql() == null) { // 无查询条件只分页
			return new ResultEntity(ResultStatus.SUCCESS, Constants.QUERY_SUCCESS).setPage(PageUtil.pageConvert(
					iInstructionRepository.findByOrderByNumbers(queryParamDto.getPageObject().getPageRequest())));
		} else if (StringUtils.isBlank(queryParamDto.getAssembleSql().getSelect())) { // 不指定任何字段
			return this.queryAll(queryParamDto);
		}
		return queryDispatcher.dispatcher(queryParamDto, Instructions.class);
	}

	@Override
	public ResultEntity edit(Instructions instruction) {
		//编辑数据
		if (StringUtils.isNotBlank(instruction.getInstructionsId())) {
			//查询原有的对象
			Instructions oldInstruction = iInstructionRepository.findById(instruction.getInstructionsId()).orElse(null);
			//判断对象是否存在
			if (oldInstruction != null) {
				//查询原始对象将非空字段复制到保存对象的空字段上,避免更新操作的时候将空字段也修改了
				Set<InstructionsData> oldInstructionsData = oldInstruction.getInstructionsData();
				Set<InstructionsData> ninstructionsData = instruction.getInstructionsData();
				for (InstructionsData instructionsData : oldInstructionsData) {
					for (InstructionsData instructionsData2 : ninstructionsData) {
						if (instructionsData.getInstructionsDataId().equals(instructionsData2.getInstructionsDataId())) {
							MyBeanUtils.copyNonNullProperties(instructionsData2,instructionsData);
						}
					}
				}
				instruction.setInstructionsData(oldInstructionsData);
				//复制类型的null值
				InstructionsType oldInstructionsType = oldInstruction.getInstructionsType();
				MyBeanUtils.copyNonNullProperties(instruction.getInstructionsType(), oldInstructionsType);
				instruction.setInstructionsType(oldInstructionsType);
				//复制指令对象的null值
				MyBeanUtils.copyNonNullProperties(instruction,oldInstruction);
				instruction = oldInstruction;
			} else {
				return new ResultEntity(ResultStatus.ERROR, ResultConstants.NO_SUCH_OBJECT);
			}
		}else {
			Set<InstructionsData> instructionsDatas = instruction.getInstructionsData();
			if (instructionsDatas != null) {
				for (InstructionsData instructionsData : instructionsDatas) {
					instructionsData.setInstructions(instruction);
				}
				instruction.setInstructionsData(instructionsDatas);
			}
		}
		//验证指令
		ResultEntity resultEntity = validate(instruction);
		if (resultEntity.getCode() == 1) {
			return resultEntity;
		}
		//保存或者更新数据
		iInstructionRepository.save(instruction);
		return new ResultEntity(ResultStatus.SUCCESS, Constants.DEAL_SUCCESS);
	
	}

	@Override
	public ResultEntity delete(String ids) {
		if (ids.contains(",")) {
			List<String> idList = Arrays.asList(ids.split(","));
			iInstructionRepository.deleteByInstructionsIdIn(idList);
		} else {
			iInstructionRepository.deleteById(ids);
		}
		return new ResultEntity(ResultStatus.SUCCESS, Constants.DELETE_SUCCESS);
	}

	@Override
	public ResultEntity validate(Instructions instructions) {
		if("".equals(instructions.getCode()) || instructions.getCode() == null ) {
			return new ResultEntity(ResultStatus.ERROR,InstructionConstants.INSTRUCTION_CODE_NULL);
		}else if (instructions.getCode().length() > 10) {
			return new ResultEntity(ResultStatus.ERROR,InstructionConstants.INSTRUCTION_CODE_LENGTH);
		}else if (instructions.getName().equals("") || instructions.getName() == null) {
			return new ResultEntity(ResultStatus.ERROR,InstructionConstants.INSTRUCTION_NAME_NULL);
		}else if (instructions.getName().length() > 20) {
			return new ResultEntity(ResultStatus.ERROR,InstructionConstants.INSTRUCTION_NAME_LENGTH);
		}
		//指令类型
		InstructionsType instructionsType = instructions.getInstructionsType();
		if ("".equals(instructionsType.getCode()) || instructionsType.getCode() == null) {
			return new ResultEntity(ResultStatus.ERROR,InstructionConstants.INSTRUCTIONTYPE_CODE_NULL);
		}else if (instructionsType.getCode().length() > 10) {
			return new ResultEntity(ResultStatus.ERROR,InstructionConstants.INSTRUCTIONTYPE_CODE_LENGTH);
		}else if (instructionsType.getName().equals("") || instructionsType.getName() == null) {
			return new ResultEntity(ResultStatus.ERROR,InstructionConstants.INSTRUCTIONTYPE_NAME_NULL);
		}else if (instructionsType.getName().length() > 20) {
			return new ResultEntity(ResultStatus.ERROR,InstructionConstants.INSTRUCTIONTYPE_NAME_LENGTH);
		}
		//指令数据
		Set<InstructionsData> instructionsDatas = instructions.getInstructionsData();
		if (instructionsDatas != null) {
			for (InstructionsData instructionsData : instructionsDatas) {
				if ("".equals(instructionsData.getEquipmentId()) || instructionsData.getEquipmentId() ==null) {
					return new ResultEntity(ResultStatus.ERROR,InstructionConstants.INSTRUCTIONDATA_EQUIPMENT_NULL);
				}else if (instructionsData.getContent().length() > 200) {
					return new ResultEntity(ResultStatus.ERROR,InstructionConstants.INSTRUCTIONDATA_CONTENT_LENGTH);
				}else if (instructionsData.getState().equals("") || instructionsData.getState() ==null) {
					return new ResultEntity(ResultStatus.ERROR,InstructionConstants.INSTRUCTIONDATA_STATE_NULL);
				}else if (instructionsData.getReturninfo().equals("") || instructionsData.getReturninfo() ==null) {
					return new ResultEntity(ResultStatus.ERROR,InstructionConstants.INSTRUCTIONDATA_RETURNINFO_NULL);
				}else if (instructionsData.getReturninfo().length() > 200) {
					return new ResultEntity(ResultStatus.ERROR,InstructionConstants.INSTRUCTIONDATA_RETURNINFO_LENGTH);
				} 
			}
		}
		// 新增时对数据进行校验判断是否已存在
		List<Instructions> insNameList = iInstructionRepository.findByName(instructions.getName());
		if (insNameList != null && insNameList.size() != 0) {
			return new ResultEntity(ResultStatus.ERROR, InstructionConstants.INSTRUCTION_NAME_EXISTS);
		}
		List<Instructions> insCodeList = iInstructionRepository.findByCode(instructions.getCode());
		if (insCodeList != null && insCodeList.size() != 0) {
			return new ResultEntity(ResultStatus.ERROR, InstructionConstants.INSTRUCTION_CODE_EXISTS);
		}
		return new ResultEntity(ResultStatus.SUCCESS,InstructionConstants.INSTRUCTION_SUCCESS);
	}
	
	// 不指定字段的通用查询
	@SuppressWarnings("serial")
	public ResultEntity queryAll(QueryParamDto queryParamDto) {
		return queryParamDto.getPageObject() != null // 判断是否分页
				? ResultEntity.page(iInstructionRepository.findAll(new Specification<Instructions>() {
					@Override
					public Predicate toPredicate(Root<Instructions> root, CriteriaQuery<?> query,
							CriteriaBuilder criteriaBuilder) {
						// 构建查询条件
						List<Predicate> predicates = QueryUtil.createQueryCondition(queryParamDto,
								criteriaBuilder, root);
						// 组装查询条件
						Predicate predicate = QueryUtil.assembleCondition(queryParamDto, criteriaBuilder,
								predicates);
						// 组装SQL
						QueryUtil.assembleSql(queryParamDto, criteriaBuilder, query, root, predicate);
						return query.getRestriction();
					}
				}, queryParamDto.getPageObject().getPageRequest()))
				: new ResultEntity(ResultStatus.SUCCESS, Constants.QUERY_SUCCESS)
						.setDataList(iInstructionRepository.findAll(new Specification<Instructions>() {
							@Override
							public Predicate toPredicate(Root<Instructions> root, CriteriaQuery<?> query,
									CriteriaBuilder criteriaBuilder) {
								// 构建查询条件
								List<Predicate> predicates = QueryUtil.createQueryCondition(queryParamDto,
										criteriaBuilder, root);
								// 组装查询条件
								Predicate predicate = QueryUtil.assembleCondition(queryParamDto, criteriaBuilder,
										predicates);
								// 组装SQL
								QueryUtil.assembleSql(queryParamDto, criteriaBuilder, query, root,
										predicate);
								return query.getRestriction();
							}
						}));
	}

	@Override
	public ResultEntity createInstructionsDatas(List<InstructionsDto> instructionsDtoList) {
		List<InstructionsData> instructionsDataList = new ArrayList<InstructionsData>();
		for (InstructionsDto instructionsDto : instructionsDtoList) {
			String instructionsId = instructionsDto.getInstructionsId();
			String equipmentId = instructionsDto.getEquipmentId();
			String strategyCode = instructionsDto.getStrategyCode();
			// 创建指令实体
			Instructions instructions = new Instructions();
			instructions.setInstructionsId(instructionsId);
			// 创建指令数据实体
			InstructionsData instructionsData = new InstructionsData();
			instructionsData.setInstructions(instructions);
			instructionsData.setEquipmentId(equipmentId);
			instructionsData.setSendstrategyCode(strategyCode);
			// 初始状态为未发送
			instructionsData.setState(InstructionsStateEnum.UNSENT.getCode());
			instructionsDataList.add(instructionsData);
		}
		instructionsDataService.edit(instructionsDataList);
		return new ResultEntity(ResultStatus.SUCCESS, Constants.INSERT_SUCCESS);
	}

}
